【图解】Android View 事件传递机制

Posted by pangrongxian on 2017-07-30
Android

欢迎访问我的博客:Android 解忧杂货店

MotionEvent — 点击事件

所有 Touch 事件都被封装成了 MotionEvent 对象,包括 Touch 的位置、时间、历史记录以及第几个手指(多指触摸)等。

当一个 MotionEvent 产生后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程。

事件类型

ACTION_DOWN : 手指刚接触屏幕

ACTION_MOVE : 手指在屏幕上移动

ACTION_UP : 手指从屏幕上松开的一瞬间

ACTION_POINTER_DOWN : (屏幕上已有触控点,再按下其他触控点)

ACTION_POINTER_UP :(屏幕上当前有多个触控点,松开非最后一个点)

ACTION_CANCEL :

每个事件都是以 ACTION_DOWN 开始 ACTION_UP 结束。

事件处理

  • 传递 —— dispatchTouchEvent() 函数

  • 拦截 —— onInterceptTouchEvent() 函数

  • 消费 —— onTouchEvent() 函数 和 OnTouchListener

处理事件的方法介绍:

dispatchTouchEvent(MotionEvent ev)

用来进行事件的分发。如果事件能够传递给当前 View,那么此方法一定会被调用,返回结果受当前 View 的 onTouchEvent() 和下级 View 的 dispatchTouchEvent()方法影响,表示是否消耗当前事件。

onInterceptTouchEvent(MotionEvent event)

在上述方法( dispatchTouchEvent() )的内部调用,用来判断是否拦截某个事件,如果当前 View 拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。

onTouchEvent(MotionEvent event)

在 dispatchTouchEvent 方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接受到事件。

传递流程

Activity ——> ViewGroup (父View) ——> View (子View,即目标View)

一图胜千言

(1) View 不处理事件流程图

(2) View 处理事件流程图

(3) View 事件被拦截的情况:

下面开始详解:

  1. 触摸事件是一连串ACTION_DOWN,ACTION_MOVE..MOVE…MOVE、最后ACTION_UP,触摸事件还有ACTION_CANCEL事件。

  2. 事件都是从ACTION_DOWN开始的,Activity的dispatchTouchEvent()首先接收到ACTION_DOWN,执行super.dispatchTouchEvent(ev),事件向下分发。

  3. dispatchTouchEvent()返回true,后续事件(ACTION_MOVE、ACTION_UP)会再传递,如果返回false,dispatchTouchEvent()就接收不到ACTION_UP、ACTION_MOVE。

情形 1 :ACTION_DOWN 事件没有被消费 流程图:

情形 2 :ACTION_DOWN 被目标 View 消费:

情形 2.1 后续ACTION_MOVE和UP在不被拦截的情况下都会去找VIEW

情形 2.2 后续的事件(ACTION_MOVE和UP)被拦截了

情形 3 ACTION_DOWN一开始就被父View(ViewGroup)拦截


android中的Touch事件都是从ACTION_DOWN开始的:

  1. 单手指操作:ACTION_DOWN—ACTION_MOVE—-ACTION_UP
  2. 多手指操作:ACTION_DOWN—ACTION_POINTER_DOWN—ACTION_MOVE–ACTION_POINTER_UP—ACTION_UP.

总结:

  1. 事件从 Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的 View(ViewGroup)开始一直往下(子 View)传递。子 View 可以通过 onTouchEvent()对事件进行处理。

  2. 事件由父 View(ViewGroup)传递给子 View,ViewGroup 可以通过 onInterceptTouchEvent()对事件做拦截,停止其往下传递。

  3. 如果事件从上往下传递过程中一直没有被停止,且最底层子 View 没有消费事件,事件会反向往上传递,这时父 View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到 Activity 的 onTouchEvent()函数。

  4. 如果 View 没有对 ACTION_DOWN 进行消费,之后的其他事件不会传递过来。

  5. OnTouchListener 优先于 onTouchEvent()对事件进行消费。
    上面的消费即表示相应函数返回值为 true。

参考博文:

彻底掌握Android的Touch触摸事件传递机制

Android 触控事件解析(Mastering the Android Touch System)

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()


Comments: